home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Utilities / Converters / Convert_MacPaint / Source / Extractors / extractor.c < prev    next >
Text File  |  1995-06-12  |  15KB  |  551 lines

  1. /***********************************************************************\
  2. Extract {PICT|FONT}, applications to extract Mac resources to separate files
  3. Copyright (C) 1993 David John Burrowes
  4.  
  5. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version.
  6.  
  7. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
  8.  
  9. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  10.  
  11. The author, David John Burrowes, can be reached at:
  12.     davidjohn@kira.net.netcom.com
  13.     David John Burrowes
  14.     1926 Ivy #10
  15.     San Mateo, CA 94403-1367
  16. \***********************************************************************/
  17.  
  18. /*
  19.     This is a 'quick hack' of aprogram.  It's goal is real
  20.     simple: Allow me to view PICT files without having to
  21.     make use of a Draw type program.  the theory being that
  22.     this way I'll be using the mac's internal pict display
  23.     engine natively, and am more apt to get accurate ideas
  24.     of how things should look.
  25.     Because this is just a quick hack for my own use, this
  26.     will not deal gracefully with error conditions.  It's
  27.     expected that one will hang and crash occasionally
  28.     when using this program.
  29.     Tough cookies.
  30.     =)
  31. */
  32.  
  33. #define EXTRACTOR_MENU_ID 128
  34. #define    FILE_MENU    129
  35.  
  36. #include <Types.h>
  37. #include <Windows.h>
  38. #include <QuickDraw.h>
  39. #include <Fonts.h>
  40. #include <Menus.h>
  41. #include <Packages.h>
  42. #include <Memory.h>
  43. #include <Desk.h>
  44. #include <OSEvents.h>
  45. #include <OSUtils.h>
  46. #include <ToolUtils.h>
  47.  
  48. #include <stdio.h>
  49. #include <string.h>
  50. #include <strings.h>        // for p2cstr and the reverse
  51. #include <Resources.h>
  52. #include <Errors.h>
  53. #include <files.h>
  54.  
  55. typedef    enum ErrorType
  56. {
  57.     NoError,
  58.     BadError,
  59.     NoResourcesFound
  60.  
  61. } ErrorType;
  62.  
  63. //
  64. //
  65. //
  66. static Boolean QuitFlag = false;
  67.  
  68. static int    storedCount = 0;
  69.  
  70. //
  71. //
  72. //
  73. AnnounceError(char* theText)
  74. {
  75.     ParamText((Str255)theText, "\p", "\p", "\p");
  76.     StopAlert(128, NULL);
  77.     return 0;
  78. }
  79.  
  80.  
  81. #if defined(DEBUG)
  82. #define    DEBUGMESSAGE(theText) {AnnounceError(theText);}
  83. #else
  84. #define    DEBUGMESSAGE(theText) {}
  85. #endif
  86.  
  87. ////////////////////////////////////////////////////////////////////////
  88. //    Routine:    FileExists
  89. //    Input:    a file name and a reference number
  90. //    Output:    True, if the file exists.  False, otherwise.
  91. //    Purpose:    This takes a file name and ref number, and checks to see if it exists.
  92. //                It does this in what must be a pretty inefficient way, but my sleep
  93. //                fogged eyes see no better in the high level routines, and a glance at the
  94. //                low level revealed nothing (but 'twas only a glance).  This asks for the
  95. //                Finder information about the file. Naturally, if the file exists, we don't
  96. //                get an error when we do this.  =)
  97. ////////////////////////////////////////////////////////////////////////
  98. Boolean FileExists (char* fullName, short refNum)
  99. {
  100.     OSErr theError;
  101.     FInfo junk;
  102.     
  103.     theError = GetFInfo(fullName, refNum, &junk);
  104.     
  105.     if (theError == fnfErr)    // Any other error means the file exists, or something else is bad 
  106.         return false;
  107.     else return true;
  108. }
  109.  
  110. ////////////////////////////////////////////////////////////////////////
  111. //    Routine:    MainGoodFileName
  112. //    Input:    a file name and a possible extension, a count of files processed, a refnum and dest name
  113. //    Output:    A pointer to the file name, modified.
  114. //    Purpose:    Given a file name and an extension, this puts them together.
  115. //                Note: if root+extension > the max file name size (31 chars),
  116. //                this removes characters from the root so they will fit.
  117. //                This is more usefull for the batch processoing of a directory than
  118. //                anything.  Note that if the file rootextension exists already, this
  119. //                will propose the name root1extension, and this will repeat as often
  120. //                as necessary to generate a unique name
  121. //    Bugs:    Actually, after 30,000 attempts, it gives up and returns the name.
  122. //                So, if someone has foo2.uue to foo30000.uue in their directory, bad
  123. //                things might happen.  I figure if they've gone through the effort of
  124. //                creating thirty thousand 'identical' files, they can deal with the consequences. =(.
  125. ////////////////////////////////////////////////////////////////////////
  126. char *ConstructFileName (char* rootFileName, char* extension, unsigned int count, int refNum)
  127. {
  128.     unsigned int        numFiles = 1;
  129.     int     rootLength;
  130.     int        totalLength;
  131.     int        extensionLength;
  132.     int        numLength;
  133.     int        maxFileNameLength = 31;
  134.     int        lengthDifference;
  135.     char*    stringNumber    = NewPtr(20);
  136.     Str255    scratch;
  137.     char    *fullName    = NewPtr(256);
  138.  
  139.     if (count > 999)
  140.         count = 0;
  141.     //
  142.     //    If the root+count+extension combination is larger than 31 characters,
  143.     //    truncate root so extension will fit
  144.     //
  145.     rootLength = strlen(rootFileName);
  146.     extensionLength = strlen(extension);
  147.     totalLength = rootLength + 3 + extensionLength;
  148.     lengthDifference = (maxFileNameLength - totalLength);
  149.     if (lengthDifference < 0)
  150.     {
  151.         strncpy(scratch, rootFileName, rootLength+lengthDifference);    // Subtract the differentce from the rootlength
  152.         scratch[rootLength+lengthDifference] = 0;
  153.     }
  154.     else
  155.     {
  156.         strcpy(scratch, rootFileName);
  157.     }
  158.     DEBUGMESSAGE("\pSprintf-ing");
  159.     sprintf(fullName, "%s%0.3u%s", scratch, count, extension);
  160.     c2pstr(fullName);
  161.  
  162.     //
  163.     //    Now, check to see if the proposed file name is already in use.  If so,
  164.     //    create a new file name with a number stuck between the root and the
  165.     //    extension. Check if this name exists, and repeat if necessary.
  166.     //
  167.     while ((FileExists(fullName, refNum) == true) && (numFiles < 30000))
  168.     {
  169.         numFiles ++;    
  170.         sprintf(stringNumber, "#%u", numFiles);
  171.         numLength = strlen(stringNumber);
  172.         //
  173.         //    add the number to the name of the file (replacing chars)
  174.         //
  175.         totalLength = rootLength+3+numLength+extensionLength;
  176.         //
  177.         //    make room for the number in case root+extension doesn't leave enough room for it
  178.         //
  179.         lengthDifference = (maxFileNameLength - totalLength);
  180.         if (lengthDifference < 0)
  181.         {
  182.             strncpy(scratch, rootFileName, rootLength+lengthDifference);
  183.             scratch[rootLength+lengthDifference] = 0;
  184.         }
  185.         else
  186.             strcpy(scratch, rootFileName);
  187.         sprintf(fullName, "%s%0.3u%s%s", scratch, count, stringNumber, extension);
  188.         c2pstr(fullName);
  189.     }
  190.     return fullName;
  191. }
  192.  
  193.  
  194.  
  195.  
  196.  
  197. /*======================================================================
  198.     function:    ExtractResourcesIn
  199.     Input:        the name of the mac paint file
  200.     Output:        none
  201.     Descript:        Given a file name and a type, copy all the resources of that type out to separate
  202.                 files
  203. \*======================================================================*/
  204. ErrorType ExtractResourcesIn(char*    filename, ResType  resourceType)
  205. {
  206.     short        refNum;
  207.     short        result;
  208.     short        homeRefNum;
  209.     short        rsrcCount = storedCount;
  210.     short        index;
  211.     short        headerindex;
  212.     short        volrefnum    = 0;
  213.     short        fileNum;
  214.     short        resID;
  215.     char*        sourceName;
  216.     char*        pasName    = NULL;
  217.     long        rsrcSize;
  218.     int            numRsrc;
  219.     long        theSize;
  220.     Ptr            tempHeader;
  221.     Handle        resource;
  222.     ResType        theResType;
  223.     Str255        resName;
  224.     ErrorType    status        = NoError;
  225.     
  226.     #if defined(DEBUG)
  227.         char*        DebugString = NewPtr(256);
  228.     #endif
  229.  
  230. //    DEBUGMESSAGE(filename);
  231.     if (strncmp(filename, "\006System", 7) == 0)
  232.         result = 0;
  233.     else
  234.         result = OpenResFile(filename);
  235.     if (result == -1)
  236.     {
  237.         AnnounceError("\pUnable to open that file!");
  238.         status = BadError;
  239.     }
  240.     else
  241.     {
  242. //        DEBUGMESSAGE("\pno error");
  243.         refNum = result;
  244.         SetResLoad(false);
  245.         numRsrc= CountResources(resourceType);
  246.         if (numRsrc > 0)
  247.         {
  248.             for (index = 1; index <= numRsrc; index++)
  249.             {
  250.                 resource = GetIndResource(resourceType, index);
  251.                 //
  252.                 //    If this resource isn't in the specified file, but in another in the lookup path,
  253.                 //    then skip it.  Additionally, don't process the resource if it has no length.
  254.                 //
  255.                 homeRefNum = HomeResFile(resource);
  256.                 rsrcSize = SizeResource(resource);
  257.                 if ((homeRefNum == refNum) && (rsrcSize != 0))
  258.                 {
  259.                     rsrcCount++;
  260.                     GetResInfo(resource, &resID, &theResType, resName);
  261.                     SetResLoad(true);
  262.                     LoadResource(resource);
  263. //                    DEBUGMESSAGE("\pLoaded the resource");
  264.                     if (resName[0] != 0)
  265.                     {
  266.                         sourceName = NewPtr(resName[0]+1);
  267.                         strncpy(sourceName, &resName[1], resName[0]);
  268.                         sourceName[resName[0]] = 0;
  269.                     }
  270.                     else
  271.                     {
  272.                         sourceName = NewPtr(filename[0]+1);
  273.                         strncpy(sourceName, &filename[1], filename[0]);
  274.                         sourceName[filename[0]] = 0;
  275.                     }
  276.  
  277.                     //
  278.                     //    Ignoring the error codes!!  way bad.
  279.                     //
  280.                     if (resourceType == 'PICT')
  281.                     {
  282.                         pasName = ConstructFileName(sourceName, ".PICT", rsrcCount, volrefnum);
  283.                         Create(pasName, volrefnum, 'MDRW', 'PICT');
  284.                     }
  285.                     else
  286.                     {
  287.                         pasName = ConstructFileName(sourceName, ".FONT", rsrcCount, volrefnum);
  288.                         Create(pasName, volrefnum, 'ExRS', 'BIN!');
  289.                     }
  290.                     result = FSOpen(pasName, volrefnum, &fileNum);
  291.                     if (result != noErr)
  292.                     {
  293.                         AnnounceError("\pUnable to open the destination file!");
  294.                         status = BadError;
  295.                     }
  296.                     else
  297.                     {
  298.                         if (resourceType == 'PICT')
  299.                         {
  300.                             //
  301.                             //    Write out a leading 512 byte header for pict files only
  302.                             //
  303.                             tempHeader = NewPtr(512);
  304.                             for (headerindex = 0; headerindex < 512; headerindex+=16)
  305.                                 strcpy((char*)&tempHeader[index], "ExtractPICT V1.0");
  306.                             theSize = 512;
  307.                             FSWrite(fileNum, &theSize, tempHeader);
  308.                             DisposPtr(tempHeader);
  309.                         }
  310.                         FSWrite(fileNum, &rsrcSize, *resource);
  311.                         FSClose(fileNum);
  312.                     }
  313.                     ReleaseResource(resource);
  314.                 }
  315.                 if (pasName != NULL)
  316.                     DisposPtr(pasName);
  317.                 pasName = NULL;
  318.             }        
  319.         }
  320.         SetResLoad(true);    // in case it wasn't already
  321.         if (refNum!= 0)
  322.             CloseResFile(refNum);
  323.     }
  324.  
  325.     storedCount = rsrcCount;
  326.     if ((rsrcCount == 0) && (status == NoError))
  327.         status = NoResourcesFound;
  328.     #if defined(DEBUG)
  329.         DisposPtr(DebugString);
  330.     #endif
  331.     return status;    // what about status
  332. }
  333.  
  334.  
  335.  
  336.  
  337.  
  338. char*    GetSourceFile()
  339. {
  340.     Point    where;
  341.     SFTypeList    myBogusList;
  342.     SFReply    reply;
  343.     Rect        badRect;
  344.     char*    newName    = NULL;
  345.  
  346.     badRect.top = 0;
  347.     badRect.left = 0;
  348.     badRect.right = 255;
  349.     badRect.bottom = 255;
  350.     
  351.     where.h = 10;
  352.     where.v = 10;
  353.     
  354.     SFGetFile(where, "\pGet a file", NULL, -1, &myBogusList, NULL, &reply);
  355.  
  356.     if (reply.good == true)
  357.     {
  358.         SetVol(NULL, reply.vRefNum);
  359.         newName = NewPtr(65);
  360.         //
  361.         //    Copying AS pascal string.
  362.         //
  363.         strncpy(newName, &(reply.fName) , 1+(reply.fName)[0]);
  364.     }
  365.     else
  366.         newName = NULL;
  367.     
  368.     return (char*) newName;
  369. }
  370.  
  371.  
  372.  
  373.  
  374. void DoMenuStuff(long  results)
  375. {
  376.     long int    menuid, menuitem;
  377.     char*    theName;
  378.     CursHandle    myCursor;
  379.     ErrorType    status     = NoError;
  380.     Boolean            foundSome;
  381.  
  382.     menuid = HiWord(results);
  383.     menuitem = LoWord(results);
  384.     if (menuid == FILE_MENU) 
  385.     {
  386.         if (menuitem == 3)
  387.             QuitFlag = true;    // Setting a global
  388.         else if (menuitem == 1)
  389.         {
  390.             theName = GetSourceFile();
  391.             if (theName != NULL)
  392.             {
  393.                 myCursor = GetCursor(watchCursor);
  394.                 SetCursor(*myCursor);
  395.                 status = NoError;
  396.                 storedCount = 0;
  397.                 #if defined(FONT)
  398.                     foundSome = false;
  399.                     status = ExtractResourcesIn(theName, 'FONT');
  400.                     if (status == NoError)
  401.                         foundSome = true;
  402.                     status = ExtractResourcesIn(theName, 'NFNT');
  403.                     if ((foundSome == true) && (status == NoResourcesFound))
  404.                         status = NoError;
  405.                 #else
  406.                     status =  ExtractResourcesIn(theName, 'PICT');
  407.                 #endif
  408.                 SetCursor(&qd.arrow);
  409.                 if (status == NoError)
  410.                     AnnounceError("\pOne or more files were written");
  411.                 else if (status == NoResourcesFound)
  412.                     AnnounceError("\pNothing was there to be extracted.");
  413.                 else
  414.                     AnnounceError("\pSome error occurred while processing!");
  415.     
  416.                 DisposPtr(theName);
  417.             }
  418.         }
  419.     }
  420.     HiliteMenu(0);
  421. }
  422.  
  423.  
  424. ////
  425. //
  426. //    The main, of course.
  427. //
  428. ////
  429. main()
  430. {
  431.     WindowPtr    tempWindow;
  432.     EventRecord    theEvent;
  433.     Handle        myMenuBar;
  434.     long int    results;
  435.     long int    location;
  436.     GrafPtr        savePort;
  437.     WindowPtr     myWindow;
  438.     TEHandle     myTextField;
  439.     int            TEXTNumChars;
  440.     Handle        TEXTHandle;
  441.     Rect        boundsRect;
  442.     char*        dumbString;
  443.  
  444.     //
  445.     //    Initthe things we need
  446.     //
  447.     InitGraf((Ptr) &qd.thePort);
  448.     InitFonts();
  449.     InitWindows();
  450.     InitMenus();
  451.     TEInit();
  452.     InitDialogs(nil);
  453.     InitCursor();
  454.     
  455.     //
  456.     //    Setup
  457.     //
  458.     FlushEvents(everyEvent, 0);
  459.     myMenuBar = GetNewMBar(EXTRACTOR_MENU_ID);
  460.     SetMenuBar (myMenuBar);
  461.     DisposHandle(myMenuBar);
  462.     DrawMenuBar();
  463.  
  464.     SetRect(&boundsRect, 10, 40, 300, 210);
  465.     myWindow = NewWindow(nil, &boundsRect, "\pAbout this app", true,
  466.         4, (WindowPtr) -1, false, 0);
  467.     QuitFlag = false;
  468.     GetPort(&savePort);
  469.     SetPort((GrafPtr) myWindow);
  470.     SetRect(&boundsRect, 0, 0, 290, 170);
  471.     TextSize(9);
  472.     myTextField = TENew(&boundsRect, &boundsRect);
  473.     SetPort((GrafPtr) savePort);
  474.  
  475.  
  476.  
  477.     #if defined(FONT)
  478.         TEXTHandle = GetResource ('TEXT', 128);
  479.     #else
  480.         TEXTHandle = GetResource ('TEXT', 129);
  481.     #endif
  482.     
  483.     TEXTNumChars = SizeResource(TEXTHandle) -1;
  484.     HLock(TEXTHandle);
  485.     TEInsert((Ptr)(*TEXTHandle), TEXTNumChars, myTextField);
  486.     HUnlock(TEXTHandle);
  487.     
  488.     TESetSelect(32767, 32767, myTextField);
  489.     TECalText(myTextField);
  490.     
  491.     //
  492.     //    I later do a OpenResFile(), and a sprintf() after it.
  493.     //    On my plus, this caused sprintf to crash, unless I had called
  494.     //    it before the openres file (which is why this is there).  it didn't
  495.     //    happen on the quadra at work.  All i can figure is that there's a bug
  496.     //    here related to openresfile which keeps the seg loader from finding the
  497.     //    code for sprintf later...
  498.     //
  499.     dumbString = NewPtr(100);
  500.     sprintf(dumbString, "Stuuupid %d", 45);
  501.     DisposPtr(dumbString);
  502.  
  503.     while (QuitFlag == false)
  504.     {
  505.         if (GetNextEvent(everyEvent, &theEvent) != true)
  506.             SystemTask();
  507.         else
  508.         {
  509.             switch (theEvent.what)
  510.             {
  511.                 case keyDown :
  512.                     results = MenuKey((theEvent.message & charCodeMask));
  513.                     DoMenuStuff(results);
  514.                     break;
  515.                 case mouseDown :
  516.                     location = FindWindow(theEvent.where, &tempWindow);
  517.                     switch (location)
  518.                     {
  519.                         case 1:
  520.                             results = MenuSelect(theEvent.where);
  521.                             DoMenuStuff(results);
  522.                             break;
  523.                         case 4 : // in drag
  524.                             boundsRect.top = 0;
  525.                             boundsRect.left = 0;
  526.                             boundsRect.right = 512;
  527.                             boundsRect.bottom = 340;    // hardcoded and GROSSS bounds rectangle
  528.                             DragWindow( myWindow, theEvent.where, &boundsRect);
  529.                             break;
  530.                     }
  531.                     break;
  532.                 case updateEvt :
  533.                     BeginUpdate(myWindow);
  534.                     GetPort(&savePort);
  535.                     SetPort((GrafPtr) myWindow);
  536.                     TEUpdate(&((*myTextField)->viewRect), myTextField);
  537.                     SetPort(savePort);
  538.                     EndUpdate(myWindow);
  539.                     break;
  540.                 case     activateEvt:
  541.                     if ((theEvent.modifiers && activeFlag) != 0)
  542.                         TEActivate (myTextField);
  543.                     else
  544.                         TEDeactivate(myTextField);
  545.                     break;
  546.             }
  547.         }
  548.     }
  549.     TEDispose(myTextField);
  550.     CloseWindow(myWindow);
  551. }